package com.blog.zip.controller;


import com.alibaba.fastjson.JSONArray;
import com.blog.zip.bean.Article;
import com.blog.zip.bean.RespBean;
import com.blog.zip.bean.Tags;
import com.blog.zip.mapper.ArticleMapper;
import com.blog.zip.service.ArticleService;
import com.blog.zip.service.GitalkService;
import com.blog.zip.util.CopyUtil;
import com.blog.zip.util.DateUtil;
import com.blog.zip.util.Markdowns;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.model.FileInfo;
import com.qiniu.util.Auth;
import lombok.extern.slf4j.Slf4j;


import org.apache.commons.io.FilenameUtils;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

//@CrossOrigin
@Slf4j
@RestController
public class ArticleController {
    private static final String ACCESS_KEY = "-Me0y3v6zAGgXQz8WvWygNO_dCOVI3EK99jCxcYv";
    private static final String SECRET_KEY = "cFbFOwHtGsTWWasNqJO5nxdwiIIAGZV7_dIoCu8-";
    private static final String BUCKET = "zipblog";
    private static final String CDN_HOST = "https://cdn.zipblog.top/";
    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    GitalkService gitalkService;

    @Autowired
    private ArticleService articleService;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    /**
     * web首页文章分页获取，文章的总数量，文章的总浏览量，标签的总量
     *
     * @desc 这块看似获取文章的接口，实则是获取首页相关数据的接口，包含文章首页内容，文章总浏览量，总数，等等
     */
    @GetMapping("/article/get")
    public Map<String, Object> getArticle(Integer pageNo, Integer pageSize, Integer cmd, HttpServletRequest request) {
        if (pageNo == null) pageNo = 1;
        if (pageSize == null) pageSize = 10;
        int offset = 0;
        offset = (pageNo - 1) * pageSize;
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        if (cmd == null) {

        } else if (cmd == 1) {
            // web index页面端数据的获取
            List<Map<String, Object>> articleList;
            List<Map<String, Object>> articlePutTop = new ArrayList<>();
            if (pageNo == 1) {

//                articlePutTop = articleMapper.getArticleTop("");
                //置顶文章
                articlePutTop = articleMapper.getArticleByIdV2(offset, -1, 1);
            }
            //非置顶
            articleList = articleMapper.getArticleByIdV2(offset, pageSize, 0);
            articlePutTop.addAll(articleList);

            Integer total = articleMapper.getArticleTotalV2();
            map.put("code", 200);
            map.put("total", total);
            map.put("data", articlePutTop);
        } else if (cmd == 2) { // 搜索
            String keyword = request.getParameter("keyword");
            list = articleMapper.searchArticle(keyword);
            map.put("data", list);
            map.put("code", 200);
        }
        return map;
    }

    private void formatValue(Object categoryTitle, Map m, String key) {
        List titles = Arrays.asList(categoryTitle.toString().split(","));
        // 去重
        List<String> listWithoutDuplicates = (List<String>) titles.stream().distinct().collect(Collectors.toList());
        String str = StringUtils.join(listWithoutDuplicates, ",");
        m.put(key, str);
    }

    @PostMapping("/article/getByPath")
    public RespBean getArticleByPath(@RequestBody Map<String, Object> payload, HttpServletRequest request) {
        Map<String, Object> article = null;
        article = articleMapper.getArticleByPath((String) payload.get("path"));
        String content = (String) article.get("articleContent");
        String html = Markdowns.toHTML(content, request);
        article.replace("articleContent", html);
        return new RespBean(200, "success", article);
    }

    /**
     * 客户端文章详情的获取
     * @param m
     * @return
     */
    @PostMapping("/article/getById")
    public Map<String, Object> getArticleById(@RequestBody Map<String, Object> m, HttpServletRequest request) throws Exception {
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> article, articleCopy;
//        article = articleMapper.getArticleByIdV3((String) m.get("id"));
        // 当cmd = 1时 管理端获取文章
        Integer cmd = (Integer) m.get("cmd");

        articleCopy = articleService.getArticleByIdV3((String) m.get("id"),cmd);

//      stringRedisTemplate.opsForValue().append("msg","hello");

        article = CopyUtil.deepClone(articleCopy);

        if (article == null || (Integer) article.get("articleStatus") == 1) {
            Map res = new HashMap();
            res.put("ret", -1);
            res.put("msg", "article no exist");
            return res;
        }
//log.info("缓存中取到的值{}",article.get("articleTitle"));
        // JSONArray jsonArray = GitalkService.getDataByCityName();
        //for(int i=0;i<jsonArray.size();i++) {
//            System.out.println(jsonArray.getJSONObject(i).get("body"));
        //}

        // 用户的点击量不可以直接去redis缓存的
        Integer articleViewCount =  articleMapper.getArticleViewCount((String) m.get("id"));

        //该文章的分类也不能从redis中取
        List articleTags = Arrays.asList(article.get("articleTags").toString().split(","));
        ArrayList<String> categoryTitles = new ArrayList<String>();
        String categoryTitle = "",categoryURI = "";
        //log.info("{}",articleTags);
        for(int i = 0;i<articleTags.size();i++){
            Map category = articleMapper.getCategoryByTagName((String) articleTags.get(i));
            if(category != null) {
                categoryTitle += (String) category.get("categoryTitle") + ',';
                categoryURI += (String) category.get("categoryURI") + ',';
            }
        }
        formatValue(categoryTitle, article, "categoryTitle");
        formatValue(categoryURI, article, "categoryURI");
//        log.info("{}",article);

        // 使用md5对密码进行加密

        String password = (String) m.get("password");
        String verify = (String) m.get("verify");
        if (!article.get("articleViewPwd").equals("")) {
            if (password != null && article.get("articleViewPwd").equals(DigestUtils.md5DigestAsHex(password.getBytes()))) {
                article.put("auth", 1);
            } else {
                article.replace("articleContent", "");
                article.put("auth", 0);
            }
        }
//        if (article.get("categoryTitle") != null) {
//            formatValue(article.get("categoryTitle"), article, "categoryTitle");
//        }
//        if (article.get("categoryURI") != null) {
//            formatValue(article.get("categoryURI"), article, "categoryURI");
//        }
        String content = (String) article.get("articleContent");
        String html = Markdowns.toHTML(content, request);
        article.replace("articleContent", html);
        article.replace("articleViewPwd", "");
        article.replace("articleViewCount",articleViewCount);
//        log.info("{}",articleViewCount);
        // 找到前一篇 后一篇
        Map params = new HashMap();
        params.put("articleCreated", article.get("articleCreated"));
        params.put("type", 1);
        Map next = articleMapper.getNeighborArticle(params);

        params.put("type", 2);
        Map prev = articleMapper.getNeighborArticle(params);

        List neighborList = new ArrayList();
        // 比当前时间小 上一篇
        // 比当前时间大 下一篇

        neighborList.add(next);
        neighborList.add(prev);

        map.put("data", article);
        map.put("neighborArticle", neighborList);
        map.put("code", 200);
        return map;
    }

    @PostMapping("/article/password")
    public Map getPasswordById(@RequestBody Map<String, Object> request) {
        Map<String, Object> map = new HashMap<>();

        return map;
    }

    /**
     * 管理端：文章的添加逻辑
     *
     * @param article
     * @return
     * @throws ParseException
     */
    @PostMapping("/article")
    public Map addArticle(@RequestBody Article article) throws ParseException {
        //System.out.println(map);
        Map<String, Object> mapData = new HashMap<>();
        mapData.put("code", 200);
        if (article.getArticleTitle() == null) {
            mapData.put("msg", "add fail, title is empty");
            mapData.put("errCode", "301");
            return mapData;
        }
        if (article.getArticleContent() == null) {
            mapData.put("msg", "add fail, content is empty");
            mapData.put("errCode", "302");
            return mapData;
        }
        if (article.getArticleTags() == null) {
            mapData.put("msg", "add fail, tags is empty");
            mapData.put("errCode", "303");
            return mapData;
        }
        articleMapper.addArticle(article);
        Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(article.getArticleCreated());
        Map<String, Object> map = new HashMap<>();
        map.put("date", DateUtil.getMonthBegin(date));
        map.put("zid", 0);
        articleMapper.addArchive(map);
//        System.out.println("文章添加后返回的id  " + article.getZid());
//        System.out.println("归档返回的id  " + map.get("zid"));
        //return new RespBean(200, 200, "add success");
        //mapData.put("data",map);
        //mapData.put("data",article);
        mapData.put("msg", "add success");
        return mapData;
    }

    @PostMapping("/article/tags")
    public RespBean addTags(Tags tags) {
        //判断是否重复 使用集合接受
        Map m;
        m = articleMapper.isRepeat(tags);
        if (m != null && !m.isEmpty()) {
            return new RespBean(301, 200, "add repeat");
        } else {
            long time = System.currentTimeMillis();
            tags.setId(time);
            Integer result = articleMapper.addTags(tags);
            return new RespBean(1, 200, "add success");
        }
    }

    @PostMapping("/tags/delete")
    public RespBean deleteTag(Tags tags) {
        Map m = articleMapper.isRepeat(tags);
//        log.info("{}", m);
        articleMapper.deleteTagArticle((String) m.get("oId"));
        articleMapper.deleteTagCategory((String) m.get("oId"));
        articleMapper.deleteTag(tags);
        return new RespBean(1, 200, "delete success");
    }

    @GetMapping("/article/tags/get")
    public Map getTags() {
        Map<String, Object> map = new HashMap<>();
        List list = new ArrayList();
        list = articleMapper.getTags();
        map.put("data", list);
        map.put("code", 200);
        return map;
    }

    /**
     * 本地图片上传的方法
     *
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("/article/img")
    public Map uploadImage(@RequestParam("fileOrigin") MultipartFile file) throws IOException {
        String fileName = file.getOriginalFilename();
        String extension = "." + FilenameUtils.getExtension(fileName);
        String newFileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + UUID.randomUUID().toString().replace("-", "") + extension;
        long size = file.getSize();
        String type = file.getContentType();
        String realPath = ResourceUtils.getURL("classpath:").getPath() + "static/files";
        String dateDirPath = realPath + "/" + new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String dataFormat = "/" + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + '/';
        File dataDir = new File(dateDirPath);
        if (!dataDir.exists()) dataDir.mkdirs();
        file.transferTo(new File(dataDir, newFileName));

        Map<String, Object> map = new HashMap<>();
        map.put("code", 200);
        map.put("msg", "upload success");
//        map.put("path", "/api/files" + dataFormat + newFileName);
        map.put("fileName", newFileName);
        return map;
    }

    /**
     * 从七牛云中获取所有的图片
     *
     * @return
     */
    @GetMapping("/article/draw/get")
    public Map<String, Object> getQiniuDrawing() {
        Configuration cfg = new Configuration(Region.region0());

        Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY);
        BucketManager bucketManager = new BucketManager(auth, cfg);
        //文件名前缀
        String prefix = "";
        //每次迭代的长度限制，最大1000，推荐值 1000
        int limit = 1000;
        //指定目录分隔符，列出所有公共前缀（模拟列出目录效果）。缺省值为空字符串
        String delimiter = "";
        //列举空间文件列表
        List list = new ArrayList();
        BucketManager.FileListIterator fileListIterator = bucketManager.createFileListIterator(BUCKET, prefix, limit, delimiter);
        while (fileListIterator.hasNext()) {
            //处理获取的file list结果
            FileInfo[] items = fileListIterator.next();
            for (FileInfo item : items) {
                if (item.mimeType.contains("image")) {
                    list.add(CDN_HOST + item.key);
                }
            }
        }
        Map<String, Object> map = new HashMap<>();
        map.put("code", 200);
        map.put("msg", "upload success");
        map.put("data", list);
        return map;

    }

    //获取七牛云的token
    @GetMapping("/article/qiniu/token")
    public Map getQiniuToken(String fname) {
        Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY);
        String upToken = auth.uploadToken(BUCKET, fname);
        Map<String, Object> map = new HashMap<>();
        map.put("token", upToken);
        map.put("code", 200);
        return map;
    }

    @PostMapping("/article/edit")
    public Map editArticle(@RequestBody Article article) throws ParseException {
        String link = article.getArticleImgURL();
        long zid = article.getZid();
        //System.out.println(link + " ------ " + zid);
        articleMapper.updateArticle((Map) article);

        Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(article.getArticleCreated());


//        articleMapper.addArchive(DateUtil.getMonthBegin(date));
        Map<String, Object> map = new HashMap<>();
        map.put("code", 200);
        return map;
    }

    @PostMapping("/article/del")
    public RespBean delArticle(@RequestParam("zid") Integer id) {
//        System.out.println(id);
        articleMapper.delArticle(id);
        return new RespBean(200, "del success");
    }

    @PostMapping("/article/recordViewCount")
    public RespBean recordViewCount(@RequestBody Map<String, Object> map) {
//        System.out.println(map);
        Map<String, Object> article = articleMapper.getArticleById((String) map.get("id"));

        if (article != null) {
            Integer count = (Integer) article.get("articleViewCount");
            count++;
            article.replace("articleViewCount", count);
            //data.setArticleViewCount(count);
//        System.out.println(data.getArticleViewCount());
            articleMapper.updateArticle(article);
            return new RespBean(200, "success");
        } else {
            return new RespBean(500, "failed");
        }
    }
}

